﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/// <summary>
/// 对数组的一些扩展
/// </summary>
public static class ArrayExtend
{
    /// <summary>
    /// <b>注：不改变原来的数组</b><br/>
    /// 类似于排行榜<br/>
    /// 往一个有序数组里插入一个元素，得到一个新数组。<br/>
    /// 插入后，取前几位返回。如 {4,3,2,1} 中插入5，则返回 {5,4,3,2}，如果扩展，则返回 {5,4,3,2,1}<br/>
    /// 如果往 { 4,3,2,1 } 中插入0，不扩展，则返回 { 4,3,2,1 }，因为0没有跻身前4<br/>
    /// </summary>
    /// <typeparam name="T">数组是什么类型的</typeparam>
    /// <param name="array">原数组</param>
    /// <param name="val">要插入的元素</param>
    /// <param name="complareFunc">判别方法.  (a,b)=>a-b 则为升序</param>
    /// <param name="isExtend">是否扩展数组长度</param>
    /// <param name="pos">插入的对象在新数组当中的索引。如果没有上榜，则保持原来的值不变</param>
    /// <returns></returns>
    public static T[] InsertOrderValue<T>(this T[] array, T val, Func<T, T, int> complareFunc, ref int pos, bool isExtend = false)
    {
        T[] temp;
        if (isExtend)
        {
            temp = new T[array.Length + 1];
            if (array.Length > 0)
                temp[temp.Length - 1] = array[array.Length - 1];
        }
        else
        {
            temp = new T[array.Length];
        }
        //插入元素
        int offset = 0;
        bool isInsert = false;
        int complare = isExtend ? temp.Length - 1 : temp.Length;
        for (int i = 0; i < complare; i++)
        {
            if (!isInsert && complareFunc(array[i], val) > 0)
            {
                temp[i + offset] = val;
                offset++;
                isInsert = true;
                pos = i;
            }
            else
            {
                temp[i] = array[i - offset];
            }
        }

        if (isExtend && offset == 0)
        {
            temp[temp.Length - 1] = val;
            pos = temp.Length - 1;
        }

        return temp;
    }
    public static T[] InsertOrderValue<T>(this T[] array, T val, Func<T, T, int> complareFunc, bool isExtend = false)
    {
        int pos = -1;
        return InsertOrderValue(array, val, complareFunc, ref pos, isExtend);
    }
    /// <summary>
    /// 遍历。<br/>
    /// 对于值类型或者有空元素的数组来说肯呢个和有问题，建议只对满元素的引用类型使用。<br/>
    /// 推荐使用 ForEachIndex
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="array"></param>
    /// <param name="action"></param>
    /// <seealso cref="ForEachIndex"/>
    public static void ForEach<T>(this T[] array, Action<T> action)
    {
        //foreach (T item in array)
        //{
        //    action?.Invoke(item);
        //}
        array.ForEachIndex(i => action?.Invoke(array[i]));
    }
    /// <summary>
    /// 遍历
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="array"></param>
    /// <param name="action">参数是索引</param>
    public static void ForEachIndex<T>(this T[] array, Action<int> action)
    {
        for (int i = 0; i < array.Length; i++)
        {
            action?.Invoke(i);
        }
    }

    /// <summary>
    /// 将某个数组转化为另一个类型的数组
    /// </summary>
    /// <typeparam name="T">初始数组元素类型</typeparam>
    /// <typeparam name="E">目标数组元素类型</typeparam>
    /// <param name="array"></param>
    /// <param name="element">从当前数组元素到目标数组元素的隐射，形参是索引</param>
    /// <returns>目标元素的数组</returns>
    public static E[] GetArrayWithIndex<T, E>(this T[] array, Func<int, E> element)
    {
        if (element == null) return null;

        E[] es = new E[array.Length];
        //for (int i = 0; i < array.Length; i++)
        //{
        //    es[i] = element.Invoke(i);
        //}
        array.ForEachIndex(i => es[i] = element.Invoke(i));

        return es;
    }

    public static void CopyTo<T>(this T[] array, T[] targetArray, int souceFrom, int targetFrom, int length)
    {
        int targetArrayIndex = targetFrom;
        int souceArrayIndex = souceFrom;
        int count = 0;
        while (count < length)
        {
            if (targetArrayIndex >= targetArray.Length || souceArrayIndex >= array.Length) break;

            targetArray[targetArrayIndex] = array[souceArrayIndex];
            count++;
            targetArrayIndex++;
            souceArrayIndex++;
        }
    }
}
